unit uOperatorStation;

interface

uses Graphics, Types, extctrls, XMLIntf, uTrackItem;

type

  TOperatorStationDirection = (osUp, osDown);

  TOperatorStation = class(TTrackItem)
  private
    aStartX, aStartY: Cardinal;
    aDayStart, aDayEnd: TDateTime;
    aIsDay: boolean;
    aRefreshTimer: TTimer;
    aDirection: TOperatorStationDirection;

    procedure CheckDay;
    procedure CreateTimer;

  public
    constructor Create(paCanvas: TCanvas; paRasterX, paRasterY: byte; paStartX, paStartY: Cardinal); overload;
    constructor Create(paCanvas: TCanvas; paRasterX, paRasterY: byte; paId: Cardinal); overload;
    destructor  Destroy;

    function  LoadFromXml(const paXmlNode: IXmlNode): boolean; override;
    procedure DrawForeground; override;
    procedure DrawBackground; override;
    function  IsOnXY(paX, paY: real): boolean; override;
    procedure Refresh(paSender: TObject);
  end;

implementation

uses SysUtils, Windows, config, uCanvasState;

const
  TOTAL_WIDTH = 17;
  TOTAL_HEIGHT = 25;
  REFRESH_INTERVAL = 1000; //ms

{ TOperatorStation }

constructor TOperatorStation.Create(paCanvas: TCanvas;  paRasterX, paRasterY: byte; paStartX, paStartY: Cardinal);
begin
  inherited Create(paCanvas, paRasterX, paRasterY);
  aStartX := paStartX;
  aStartY := paStartY;
  CreateTimer;
end;

constructor TOperatorStation.Create(paCanvas: TCanvas; paRasterX, paRasterY: byte; paId: Cardinal);
begin
  inherited Create(paCanvas, paRasterX, paRasterY);
  SetId(paId);
  aStartX := 0;
  aStartY := 0;
  CreateTimer;
end;

procedure TOperatorStation.DrawForeground;
var
  originalCanvasState: TCanvasState;
  penColor, brushColor: TColor;
begin
  originalCanvasState.CopyFromCanvas(Canvas);

  if aIsDay then
    penColor := COLOR_DARK_GRAY
  else
    penColor := COLOR_LIGHT_BLUE;

  brushColor := COLOR_BACKGROUND;

  Canvas.Brush.Color := brushColor;
  Canvas.Pen.Color := penColor;
  Canvas.Pen.Width := 1;

  Canvas.Rectangle(aStartX * RasterX - TOTAL_WIDTH div 2,
                   aStartY * RasterY - TOTAL_HEIGHT div 2,
                   aStartX * RasterX + (TOTAL_WIDTH + 1) div 2,
                   aStartY * RasterY + (TOTAL_HEIGHT + 1) div 2);

  Canvas.MoveTo(aStartX * RasterX - TOTAL_WIDTH div 2 + 5, aStartY * RasterY);
  Canvas.LineTo(aStartX * RasterX + (TOTAL_WIDTH + 1) div 2 - 5, aStartY * RasterY);

  Canvas.Brush.Color := Canvas.Pen.Color;

  if aDirection = osUp then
    Canvas.Rectangle(aStartX * RasterX - TOTAL_WIDTH div 2 + 7,
                     aStartY * RasterY + 2,
                     aStartX * RasterX + (TOTAL_WIDTH + 1) div 2 - 7,
                     aStartY * RasterY + 5)
  else
    Canvas.Rectangle(aStartX * RasterX - TOTAL_WIDTH div 2 + 7,
                     aStartY * RasterY - 4,
                     aStartX * RasterX + (TOTAL_WIDTH + 1) div 2 - 7,
                     aStartY * RasterY - 1);

  originalCanvasState.CopyToCanvas(Canvas);
end;

destructor TOperatorStation.Destroy;
begin
  aRefreshTimer.Destroy;
  inherited;
end;

procedure TOperatorStation.DrawBackground;
var
  originalPenColor: TColor;
  originalBrushColor: TColor;
  originalPenWidth: Integer;
  rect: TRect;
begin
  originalPenColor := Canvas.Pen.Color;
  originalBrushColor := Canvas.Brush.Color;
  originalPenWidth := Canvas.Pen.Width;

  Canvas.Brush.Color := COLOR_BACKGROUND;
  Canvas.Pen.Color := COLOR_BACKGROUND;
  Canvas.Pen.Width := 0;

  rect.Left := aStartX * RasterX - TOTAL_WIDTH div 2 + 1;
  rect.Right := rect.Left + TOTAL_WIDTH - 2;
  rect.Top := aStartY * RasterY - TOTAL_HEIGHT div 2 + 1;
  rect.Bottom := rect.Top + TOTAL_HEIGHT - 2;

  Canvas.FillRect(rect);

  Canvas.Pen.Color := originalPenColor;
  Canvas.Brush.Color := originalBrushColor;
  Canvas.Pen.Width := originalPenWidth;
end;

function TOperatorStation.IsOnXY(paX, paY: real): boolean;
begin
  result := (paX = aStartX) and (paY = aStartY);
end;

function TOperatorStation.LoadFromXml(const paXmlNode: IXmlNode): boolean;
begin
  try
    aStartX := strToInt(paXmlNode.Attributes[ATR_START_X]);
    aStartY := strToInt(paXmlNode.Attributes[ATR_START_Y]);
    aDayStart := StrToTime(paXmlNode.Attributes[ATR_START_DAY]);
    aDayEnd := StrToTime(paXmlNode.Attributes[ATR_END_DAY]);

    if paXmlNode.Attributes[ATR_DIRECTION] = 'down' then
      aDirection := osDown
    else
      aDirection := osUp;

    result := true;
  except
    result := false;
  end;
end;

procedure TOperatorStation.CheckDay;
var
  time: TDateTime;
begin
  time := GetTime;

  if ((time >= aDayStart) and (time < aDayEnd)) then
    aIsDay := true
  else
    aIsDay := false;
end;

procedure TOperatorStation.CreateTimer;
begin
  aRefreshTimer := TTimer.Create(nil);
  aRefreshTimer.Interval := REFRESH_INTERVAL;
  aRefreshTimer.OnTimer := Refresh;
  aRefreshTimer.Enabled := true;
end;

procedure TOperatorStation.Refresh(paSender: TObject);
var
  wasDay: boolean;
begin
  wasDay := aIsDay;
  CheckDay;
  if not(wasDay = aIsDay) then
  begin
    DrawBackground;
    DrawForeground;
  end;
end;

end.
